/* 深度监测 算法本地化处理 */

const MAX_WIDTH = 60 //缓存数据的最大宽度
const STATE_WIDTH = 3 //5帧连续稳定时判定总体稳定
const FILTER_SCORE = 70 //过滤此分数下的数据

const MAX_FILTER_WIDTH = 30
const MIN_FILTER_WIDTH = 3

const DIFF_WIDTH = 10

var leftInput = []
var rightInput = []
var leftFilter = []
var rightFilter = []

var leftStateHistory = [],
	rightStateHistory = []
var lastLeftOut = 0,
	lastRightOut = 0;
var lastState = 100;
var leftOffset = 0,
	rightOffset = 0;

//阻抗绝对值对称性
var symmetry = [];

//阻抗变化率对称性
var changeRateSymmetry = [];
var leftStart = 0,
	rightStart = 0;
var leftCache = [],
	rightCache = [];
var cnt = 0;

// 初始化 所有变量
export function initVariable() {
	leftInput = []
	rightInput = []
	leftFilter = []
	rightFilter = []
	leftStateHistory = [],
		rightStateHistory = []
	lastLeftOut = 0,
		lastRightOut = 0;
	lastState = 100;
	leftOffset = 0,
		rightOffset = 0;
	//阻抗绝对值对称性
	symmetry = [];
	//阻抗变化率对称性
	changeRateSymmetry = [];
	leftStart = 0,
		rightStart = 0;
	leftCache = [],
		rightCache = [];
	cnt = 0;
}
/**
 * 算法入口函数
 * @param {Object} dataInput 左右脑数据
 */
export function process(dataInput) {
	let target = new Object()
	let deepFilterRes = filter(dataInput)
	let offsetDataRes = offset(deepFilterRes)
	target.left = parseFloat(deepFilterRes.left)
	target.right = parseFloat(deepFilterRes.right)
	target.allState = offsetDataRes.state
	target.leftOffset = offsetDataRes.left
	target.rightOffset = offsetDataRes.right
	target.leftState = deepFilterRes.leftState
	target.rightState = deepFilterRes.rightState
	return target
}

function filter(input) {
	var res = new Object()
	updateHistoryInput(parseFloat(input.left), parseFloat(input.right))
	if (leftInput.length < 3 || rightInput.length < 3) {
		res.left = parseFloat(input.left)
		res.leftState = 0
		res.right = parseFloat(input.right)
		res.rightState = 0
		return res
	}

	//自适应滤波，输入历史 数据 ，输出
	let left = Lmsfilter.filter(leftInput)
	let right = Lmsfilter.filter(rightInput)
	updateHistoryFilter(left, right)
	let leftState = waveRecognize(leftFilter)
	let rightState = waveRecognize(rightFilter)

	res.left = left
	res.leftState = leftState
	res.right = right
	res.rightState = rightState
	return res
}

function updateHistoryFilter(left, right) {
	leftFilter.push(left);
	rightFilter.push(right);
	if (leftFilter.length > MAX_WIDTH) {
		leftFilter.shift();
	}
	if (rightFilter.length > MAX_WIDTH) {
		rightFilter.shift();
	}
}

function updateHistoryInput(left, right) {
	leftInput.push(left);
	rightInput.push(right);
	if (leftInput.length > MAX_WIDTH) {
		leftInput.shift();
	}
	if (rightInput.length > MAX_WIDTH) {
		rightInput.shift();
	}
}

// 自适应滤波器 （最小均方差线性拟合）
var Lmsfilter = {
	filter: function(dat) {
		if (dat.length < MIN_FILTER_WIDTH) return dat[dat.length - 1]
		if (dat.length <= MAX_FILTER_WIDTH) {
			return fit(dat)[dat.length - 1]
		}
		let temp = fit(dat.slice(dat.length - MAX_FILTER_WIDTH, dat.length))
		return temp[temp.length - 1]
	}

}

function fit(dat) {
	let a = 0,
		b = 0;
	let target = []
	let ySum = 0,
		xSum = 0,
		xySum = 0,
		xxSum = 0;
	dat.forEach(d => {
		ySum += d;
	});
	for (let i = 0; i < dat.length; i++) {
		xSum += i;
		xySum += i * dat[i];
		xxSum += i * i;
	}
	b = (ySum * xxSum - xSum * xySum) / (dat.length * xxSum - xSum * xSum);
	a = (xySum - xSum * b) / xxSum
	for (let i = 0; i < dat.length; i++) {
		target.push(a * i + b)
	}
	return target
}

// 跳变信号偏置过滤器
function offset(input) {
	leftStateHistory.push(input.leftState);
	rightStateHistory.push(input.rightState);
	if (leftStateHistory.length > STATE_WIDTH) {
		leftStateHistory.shift();
		rightStateHistory.shift();
	}

	//寻找当前左右脑最近数据中的状态最小值
	//开启偏置时，为保证对称，左右脑中有一个不稳定时,则判断都不稳定
	var minState = 100
	for (let i = 0; i < leftStateHistory.length; i++) {
		if (leftStateHistory[i] < minState) minState = leftStateHistory[i];
		if (rightStateHistory[i] < minState) minState = rightStateHistory[i];
	}
	let res = new Object()
	res.state = minState
	if (minState == 0) {
		res.left = input.left
		res.right = input.right
	} else if (minState > FILTER_SCORE) {
		if (lastState <= FILTER_SCORE) {
			//从不稳定恢复到稳定时刻更新偏置
			leftOffset = lastLeftOut - input.left
			rightOffset = lastRightOut - input.right
		}
		res.left = input.left + leftOffset
		res.right = input.right + rightOffset
	} else {
		//滤掉不稳定时的数据
		res.left = lastLeftOut
		res.right = lastRightOut
	}

	lastLeftOut = res.left
	lastRightOut = res.right
	lastState = res.state
	return res
}

// 判定 输入连续阻抗稳定性
function waveRecognize(list) {
	if (list.length < DIFF_WIDTH + 10) return 0;
	var diffFitList = []
	for (let i = 0; i < list.length - DIFF_WIDTH; i++) {
		let temp = []
		for (let j = 0; j < DIFF_WIDTH; j++) {
			temp.push(list[i + j])
		}
		//求取线性拟合曲线 x: 0~length -1
		let line = fit(temp)
		let b = line[0]
		let a = line[1] - b
		diffFitList.push(a * 100)
	}
	//累加
	let sum = 0
	for (let i = 0; i < diffFitList.length; i++) {
		sum += diffFitList[i]
	}

	//均值
	let avg = parseFloat(sum / diffFitList.length)
	//窗口斜率标准差
	let deviations = 0;
	for (let i = 0; i < diffFitList.length; i++) {
		deviations += (diffFitList[i] - avg) * (diffFitList[i] - avg)
	}
	deviations /= diffFitList.length
	let target = parseInt(60.0 + (35.0 - Math.sqrt(deviations)) / 35.0 * 40.0)
	if (target > 100) target = 100;
	if (target <= 0) target = 1
	return target
}

/**
 * @param {Object} left
 * @param {Object} right
 * @param {Object} regEvaluationScore 当前REG状态评估分数（从服务器获取 0~100）
 * @param {Object} modelData 0~100的评估分数，前10帧均为100
 */
export function evaluation(left, right, regEvaluationScore, modelData) {
	cnt++;
	leftCache.push(left);
	rightCache.push(right);

	let score = 0;
	if (leftCache.length > 100) {
		leftCache.shift();
		rightCache.shift();
	}
	if (cnt < 10) {
		leftStart += left;
		rightStart += right;
		score = 100;
	} else if (cnt == 10) {
		leftStart += left;
		rightStart += right;
		leftStart /= 10.0;
		rightStart /= 10.0;
		score = 100;
	} else {
		let symmetryScore = symmetryEvaluation();
		let impChangeScore = impChangeEvaluation(modelData.impRange);
		score = parseInt(symmetryScore * 0.6 + impChangeScore * 0.2 + regEvaluationScore * 0.2);
	}
	return score;
}

/**
 * 左右脑变化对称性评估（1分40秒之内的对称性评估，后面捕捉到真实的卒中曲线特征时可以适当延长或缩短）
 *
 * @return {@link Integer}
 */
function symmetryEvaluation() {
	//统计查看变化阈值,给出差异分数0~100
	let leftCurrent = 0;
	let rightCurrent = 0;
	for (let i = leftCache.length - 5; i < leftCache.length; i++) {
		leftCurrent += leftCache[i];
		rightCurrent += rightCache[i];
	}
	leftCurrent /= 5.0;
	rightCurrent /= 5.0;

	let leftBase = 0;
	let rightBase = 0;
	for (let i = 0; i < 5; i++) {
		leftBase += leftCache[i];
		rightBase += rightCache[i];
	}
	leftBase /= 5.0;
	rightBase /= 5.0;

	let leftChangeRate = (leftCurrent - leftBase) / leftBase;
	let rightChaneRate = (rightCurrent - rightBase) / rightBase;
	//计算左右脑变化差异，越接近0越好
	let symmetryCurrent = Math.abs(leftChangeRate - rightChaneRate);
	changeRateSymmetry.push(symmetryCurrent);
	if (changeRateSymmetry.length > 40) {
		changeRateSymmetry.shift();
	}
	//计算标准参考值
	let standardRef = Math.abs(leftBase - rightBase) / ((leftBase + rightBase) / 2);
	//最大0.05，该标准参考值的最大值以后可以考虑做进用户模型参数之内
	//这里必须考虑到左右脑阻抗绝对值的不一致（电极接触阻抗、电极位置等因素导致），而血容积变化到阻抗变化是非线性的负相关，
	//则同样灌注压变化时，左右脑变化率也极有可能不一致
	//这里假定在0.005~0.05范围内二者是线性的
	if (standardRef > 0.2) {
		standardRef = 0.2;
	}
	if (standardRef < 0) {
		standardRef = 0;
	}
	let maxRef = 0.05 * (1 + standardRef);
	let minRef = 0.005;

	let score = 0;
	for (let d of changeRateSymmetry) {
		if (d <= minRef) {
			score += 100.0;
		} else if (d <= maxRef) {
			score += (1.0 - (d - minRef) / (maxRef - minRef)) * 100.0;
		}
	}
	score /= 100.0;
	return parseInt(score * (100.0 / changeRateSymmetry.length));
}


/**
 * 阻抗绝对值变化评估
 *
 * @param range 个人阻抗变化阈值范围
 * @return {@link Integer}
 */
function impChangeEvaluation(range) {
	let left = 0;
	let right = 0;
	for (let i = 0; i < leftCache.length; i++) {
		left += leftCache[i];
		right += rightCache[i];
	}
	left /= leftCache.length;
	right /= leftCache.length;
	let score = 100 - parseInt((Math.abs(left + right - leftStart - rightStart) / 2.0) / range * 100.0);
	if (score < 0) {
		score = 0;
	}
	if (score > 100) {
		score = 100;
	}
	return score;
}